﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ArtMath.Core.Data
{
    /// <summary>
    /// 区间
    /// </summary>
    [Serializable]
    public struct Span
    {
        /// <summary>
        /// 全集
        /// </summary>
        public static readonly Span UniversalSet = new Span(new SpanExtreme() { Value = double.NegativeInfinity }, 
            new SpanExtreme() { Value = double.PositiveInfinity });
        /// <summary>
        /// 区间一端
        /// </summary>
        public struct SpanExtreme
        {
            /// <summary>
            /// 是否闭合
            /// </summary>
            public bool IsClosed { get; set; }
            double val;
            /// <summary>
            /// 值
            /// </summary>
            public double Value
            {
                get { return val; }
                set
                {
                    val = value;
                    if (double.IsInfinity(val))
                    {
                        IsClosed = false;
                    }
                }
            }
            public SpanExtreme(bool closed, double value)
            {
                IsClosed = closed;
                val = 0;
                Value = value;
            }
            public static bool operator ==(SpanExtreme l, SpanExtreme r)
            {
                return l.IsClosed == r.IsClosed && l.Value == r.Value;
            }
            public static bool operator !=(SpanExtreme l, SpanExtreme r)
            {
                return !(l == r);
            }
        }
        public SpanExtreme Left { get; set; }
        public SpanExtreme Right { get; set; }
        public Span(bool lClosed, double lValue, bool rClosed, double rValue)
        {
            Left = new SpanExtreme(lClosed, lValue);
            Right = new SpanExtreme(rClosed, rValue);
        }
        public Span(SpanExtreme left, SpanExtreme right)
        {
            Left = left;
            Right = right;
        }
        public static bool operator ==(Span l, Span r)
        {
            return l.Left == r.Left && l.Right == r.Right;
        }
        public static bool operator !=(Span l, Span r)
        {
            return !(l == r);
        }
        public bool InSpan(double value)
        {
            if (value > Left.Value && value < Right.Value) return true;
            if (value == Left.Value && Left.IsClosed) return true;
            if (value == Right.Value && Right.IsClosed) return true;
            return false;
        }
        public Span? Intersect(Span span)
        {
            if (this == UniversalSet) return span;
            if (span == UniversalSet) return this;
            if (double.IsPositiveInfinity(Right.Value))
            {
                if (double.IsNegativeInfinity(span.Left.Value))
                {
                    if (span.Right.Value > Left.Value)
                    {
                        return new Span(Left, span.Right);
                    }
                    else if (span.Right.Value == Left.Value)
                    {
                        if (span.Right.IsClosed && Left.IsClosed)
                        {
                            return new Span(Left, span.Right);
                        }
                    }
                }
                else
                {
                    if (Left.Value < span.Left.Value)
                    {
                        return span;
                    }
                    else if (Left.Value > span.Left.Value)
                    {
                        if (double.IsPositiveInfinity(span.Right.Value))
                        {
                            return this;
                        }
                        else
                        {
                            if (span.Right.Value > Left.Value)
                            {
                                return new Span(Left, span.Right);
                            }
                            else if (span.Right.Value == Left.Value)
                            {
                                if (span.Right.IsClosed && Left.IsClosed)
                                {
                                    return new Span(Left, span.Right);
                                }
                            }
                        }
                    }
                    else
                    {
                        return new Span(Left.IsClosed ? span.Left : span.Left.IsClosed ? Left : new SpanExtreme(false, Left.Value), span.Right);
                    }
                }
            }
            else if (double.IsNegativeInfinity(Left.Value))
            {
                if (double.IsPositiveInfinity(span.Right.Value))
                {
                    if (span.Left.Value < Right.Value)
                    {
                        return new Span(span.Left, Right);
                    }
                    else if (span.Left.Value == Right.Value)
                    {
                        if (span.Left.IsClosed && Right.IsClosed)
                        {
                            return new Span(span.Left, Right);
                        }
                    }
                }
                else
                {
                    if (Right.Value > span.Right.Value)
                    {
                        return span;
                    }
                    else if (Right.Value < span.Right.Value)
                    {
                        if (double.IsNegativeInfinity(span.Left.Value))
                        {
                            return this;
                        }
                        else
                        {
                            if (span.Left.Value < Right.Value)
                            {
                                return new Span(span.Left, Right);
                            }
                            else if (span.Left.Value == Right.Value)
                            {
                                if (span.Left.IsClosed && Right.IsClosed)
                                {
                                    return new Span(span.Left, Right);
                                }
                            }
                        }
                    }
                    else
                    {
                        return new Span(span.Left, Right.IsClosed ? span.Right : span.Right.IsClosed ? Right : new SpanExtreme(false, Left.Value));
                    }
                }
            }
            else
            {
                if (double.IsPositiveInfinity(span.Right.Value))
                {
                    if (Left.Value > span.Left.Value)
                    {
                        return this;
                    }
                    else if (Left.Value < span.Left.Value)
                    {
                        if (span.Left.Value < Right.Value)
                        {
                            return new Span(span.Left, Right);
                        }
                        else if (span.Left.Value == Right.Value)
                        {
                            if (span.Left.IsClosed && Right.IsClosed)
                            {
                                return new Span(span.Left, Right);
                            }
                        }
                    }
                    else
                    {
                        return new Span(Left.IsClosed ? span.Left : span.Left.IsClosed ? Left : new SpanExtreme(false, Left.Value), Right);
                    }
                }
                else if (double.IsNegativeInfinity(span.Left.Value))
                {
                    if (span.Right.Value > Right.Value)
                    {
                        return this;
                    }
                    else if (Right.Value > span.Right.Value)
                    {
                        if (Left.Value < span.Right.Value)
                        {
                            return new Span(Left, span.Right);
                        }
                        else if (span.Right.Value == Left.Value)
                        {
                            if (span.Right.IsClosed && Left.IsClosed)
                            {
                                return new Span(Left, span.Right);
                            }
                        }
                    }
                    else
                    {
                        return new Span(Left, Right.IsClosed ? span.Right : span.Right.IsClosed ? Right : new SpanExtreme(false, Right.Value));
                    }
                }
                else
                {
                    if (Left.Value < span.Left.Value)
                    {
                        if (Right.Value > span.Right.Value)
                        {
                            return span;
                        }
                        else if (Right.Value < span.Right.Value)
                        {
                            if (Right.Value > span.Left.Value)
                            {
                                return new Span(span.Left, Right);
                            }
                            else if (Right.Value == span.Left.Value)
                            {
                                if (span.Left.IsClosed && Right.IsClosed)
                                {
                                    return new Span(span.Left, Right);
                                }
                            }
                        }
                        else
                        {
                            return new Span(span.Left, Right.IsClosed ? span.Right : span.Right.IsClosed ? Right : new SpanExtreme(false, Right.Value));
                        }
                    }
                    else if (Left.Value > span.Left.Value)
                    {
                        if (Left.Value < span.Right.Value)
                        {
                            if (Right.Value > span.Right.Value)
                            {
                                return new Span(Left, span.Right);
                            }
                            else if (Right.Value < span.Right.Value)
                            {
                                return this;
                            }
                            else
                            {
                                return new Span(Left, Right.IsClosed ? span.Right : span.Right.IsClosed ? Right : new SpanExtreme(false, Right.Value));
                            }
                        }
                        else if (Left.Value == span.Right.Value)
                        {
                            if (Left.IsClosed && span.Right.IsClosed)
                            {
                                return new Span(Left, span.Right);
                            }
                        }
                    }
                    else
                    {
                        if (Right.Value < span.Right.Value)
                        {
                            return new Span(Left.IsClosed ? span.Left : span.Left.IsClosed ? Left : new SpanExtreme(false, Left.Value), Right);
                        }
                        else if (Right.Value > span.Right.Value)
                        {
                            return new Span(Left.IsClosed ? span.Left : span.Left.IsClosed ? Left : new SpanExtreme(false, Left.Value), span.Right);
                        }
                        else
                        {
                            return new Span(Left.IsClosed ? span.Left : span.Left.IsClosed ? Left : new SpanExtreme(false, Left.Value),
                                Right.IsClosed ? span.Right : span.Right.IsClosed ? Right : new SpanExtreme(false, Right.Value));
                        }
                    }
                }
            }
            return null;
        }
    }
}
